
#include <stdio.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>

#define MAX_REQUESTS 650
#define BUFFER_SIZE 8192
#define SERVER_IP "183.240.99.58" // 百度的IP地址
#define SERVER_PORT 80            // HTTP默认端口


int count = 0; // 请求成功数

// HTTP请求参数与结果
typedef struct
{
    int n;               // 请求序号
    const char *host;    // 服务器IP或域名
    int port;            // 端口（HTTP默认80）
    const char *path;    // 请求路径（如"/index.html"）
    char response[8192]; // 存储响应数据
    int resp_len;        // 响应长度
    int error;           // 错误码（0表示成功）
} HTTPRequest;

// 协程函数：处理单个HTTP请求
void http_request(void *arg)
{
    HTTPRequest *req = (HTTPRequest *)arg;
    req->error = 0; // 初始化错误码

    // 1. 创建非阻塞socket（库自动设置O_NONBLOCK）
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0)
    {
        req->error = -1;
        printf("请求 %s:%d 失败：创建socket失败\n", req->host, req->port);
        return;
    }


    // 2. 解析服务器地址（简化示例：直接用IP，实际可加域名解析）
    struct sockaddr_in addr;
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(req->port);
    if (inet_pton(AF_INET, req->host, &addr.sin_addr) <= 0)
    {
        req->error = -2;
        printf("请求 %s:%d 失败：无效IP\n", req->host, req->port);
        close(sockfd);
        return;
    }

    if (connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
    {
        req->error = -3;
        printf("请求 %s:%d 失败：连接超时/拒绝\n", req->host, req->port);
        close(sockfd);
        return;
    }


    char http_req[1024];
    snprintf(http_req, sizeof(http_req),
             "GET %s HTTP/1.1\r\n"
             "Host: %s:%d\r\n"
             "Connection: close\r\n\r\n",
             req->path, req->host, req->port);

    // 5. 发送请求（IO等待时协程自动挂起）
    ssize_t send_len = send(sockfd, http_req, strlen(http_req), 0);
    if (send_len <= 0)
    {
        req->error = -4;
        printf("请求 %s:%d 失败：发送数据失败\n", req->host, req->port);
        close(sockfd);
        return;
    }

    // 6. 接收响应（IO等待时协程自动挂起，循环读取完整响应）
    req->resp_len = 0;
    while (1)
    {
        ssize_t recv_len = recv(sockfd,
                                req->response + req->resp_len,
                                sizeof(req->response) - req->resp_len - 1,
                                0); // recv是阻塞的，但是不用担心挑不出循环，因为服务器发完响应之后就会关闭连接，从而使得recv返回0，跳出循环。
                                // sizeof(req->response) - req->resp_len - 1 = 0 的时候recv_len也会返回0，也会跳出循环。
        if (recv_len <= 0)
        {
            break; // 连接关闭或出错或buffer满了，退出循环
        }
        req->resp_len += recv_len;
        
    }
    req->response[req->resp_len] = '\0'; // 字符串结尾

    // 7. 关闭连接，标记成功
    close(sockfd);
    printf("请求 %d 完成，响应长度：%d字节\n",
           req->n, req->resp_len);
    count++;
}

HTTPRequest *HTTPRequest_init(int n)
{
    if (n <= 0)
    {
        fprintf(stderr, "无效的大小（必须为正数）\n");
        return NULL;
    }

    // 2. 动态分配n个HTTPRequest的内存
    HTTPRequest *reqs = (HTTPRequest *)malloc(n * sizeof(HTTPRequest));
    if (reqs == NULL)
    { // 检查分配是否成功
        perror("内存分配失败");
        return NULL;
    }

    // 3. 初始化每个元素（替代原来的静态初始化列表）
    for (int i = 0; i < n; i++)
    {
        reqs[i].host = SERVER_IP;
        reqs[i].port = SERVER_PORT;
        reqs[i].path = "/";
        reqs[i].n = i + 1; // 设置请求序号
    }

    return reqs;
}

int main()
{
    // 定义n个不同的HTTP请求（可扩展为更多）,这里均为百度，模拟同时向百度发送n个http请求
    HTTPRequest *reqs = HTTPRequest_init(MAX_REQUESTS);

    for (int i = 0; i < MAX_REQUESTS; i++)
    {
        http_request(&reqs[i]);
    }
    free(reqs);


    if (count == MAX_REQUESTS)
    {
        printf("所有请求均已成功完成！, 请求数为 %d\n", count);
    }
    else
    {
        printf("部分请求未完成，成功请求数：%d\n", count);
    }

    return 0;
}